package org.penguin.study.bk.exception

import org.penguin.study.bk.base.api.Return
import org.penguin.study.bk.constant.HttpStatus
import org.slf4j.LoggerFactory
import org.springframework.dao.DataIntegrityViolationException
import org.springframework.dao.EmptyResultDataAccessException
import org.springframework.validation.BindException
import org.springframework.validation.BindingResult
import org.springframework.validation.FieldError
import org.springframework.web.HttpRequestMethodNotSupportedException
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.MissingServletRequestParameterException
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RestControllerAdvice
import javax.validation.ConstraintViolationException


@RestControllerAdvice
class GlobalExceptionHandler {

    companion object {
        private val logger = LoggerFactory.getLogger(GlobalExceptionHandler::class.java)
    }

    @ExceptionHandler(value = [ConstraintViolationException::class, BindException::class, MethodArgumentNotValidException::class])
    fun validationExceptionHandler(exception: Exception?): Return<*> {
        var bindResult: BindingResult? = null
        var msg = StringBuilder()
        when (exception) {
            is ConstraintViolationException -> {
                msg = msg.append(exception.message)
            }
            is BindException -> {
                bindResult = exception.bindingResult
            }
            is MethodArgumentNotValidException -> {
                bindResult = exception.bindingResult
            }
        }

        if (bindResult != null && bindResult.hasErrors()) {
            logger.error("Validation Binding Exception: {}", bindResult.allErrors)
            for (objectError in bindResult.allErrors) {
                val fieldError = objectError as FieldError
                msg = msg.append(fieldError.field).append(": ")
                    .append(fieldError.defaultMessage).append(", ")
            }
        }
        logger.error("Validation Exception: {}", msg)
        return Return.error(HttpStatus.Payment_Required,msg.toString())
    }

    @ExceptionHandler(value = [MissingServletRequestParameterException::class])
    fun parameterExceptionHandler(e: MissingServletRequestParameterException): Return<*> {
        return Return.error(HttpStatus.Payment_Required,"无效的参数: ${e.message}")
    }

    @ExceptionHandler(value = [EmptyResultDataAccessException::class])
    fun resourceNotFoundException(e: EmptyResultDataAccessException): Return<*> {
        return Return.error(HttpStatus.Not_Found,"没找到您想要的对象: ${e.message}")
    }

    /**
     * 405 Method Not Allowed
     */
    @ExceptionHandler(value = [HttpRequestMethodNotSupportedException::class])
    fun httpRequestMethodNotSupportedException(e: HttpRequestMethodNotSupportedException): Return<*> {
        return Return.error(HttpStatus.Method_Not_Allowed,"不支持${e.method}的请求方法,支持${e.supportedMethods!!.joinToString { it }}等请求方式。")
    }

    @ExceptionHandler(value = [NullPointerException::class])
    fun nullPointerException(e: NullPointerException): Return<*> {
        return Return.error(HttpStatus.Internal_Server_Error, "服务端错误: ${e.message}")
    }

    @ExceptionHandler(value = [DataIntegrityViolationException::class])
    fun dataIntegrityViolationException(e: DataIntegrityViolationException): Return<*> {
        return Return.error(HttpStatus.Internal_Server_Error, "数据库约束错误: ${e.message}")
    }

//    @ResponseStatus(HttpStatus.BAD_REQUEST)
//    @ExceptionHandler(MethodArgumentNotValidException::class)
//    fun handleValidationExceptions(
//            ex: MethodArgumentNotValidException): Map<String, String?>? {
//        val errors: MutableMap<String, String?> = HashMap()
//        ex.bindingResult.allErrors.forEach(Consumer { error: ObjectError ->
//            val fieldName = (error as FieldError).field
//            val errorMessage = error.getDefaultMessage()
//            errors[fieldName] = errorMessage
//        })
//        return errors
//    }
}